﻿//========================================================= 
/**@file HidCmdDriver.h
 * @brief HID设备命令驱动
 * 
 * @date 2016-08-31   20:50:29
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_HIDCMDDRIVER_H_
#define _LIBZHOUYB_HIDCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../../base_device/win32/HidDevice.h"
using zhou_yb::base_device::env_win32::HidDevice;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// HID设备命令驱动
class HidCmdDriver : public CommonCmdDriver
{
protected:
    Ref<IBaseDevice> _activeDev;
    Ref<IInteractiveTrans> _activeTrans;
    Ref<ITimeoutBehavior> _activeTimeout;

    HidFixedCmdAdapter<HidDevice> _hidcmd;
    HidDevice _hiddev;
public:
    HidCmdDriver() : CommonCmdDriver()
    {
        _hidcmd.SelectDevice(_hiddev);
        _activeTrans = _hidcmd;
        _activeDev = _hiddev;
        _activeTimeout = _hiddev;

        _errGetter.Add(_hiddev);
        
        _logSetter.select(_hiddev);

        _RegisteCMD(HidCmdDriver, EnumDevice);

        _RegisteIBaseDeviceCMD(HidCmdDriver);
        _RegisteIInteractiveTransCMD(HidCmdDriver);
        _RegisteITimeoutCMD(HidCmdDriver);
        _RegisteCancelCMD(HidCmdDriver);

        _RegisteInterfaceCMD(HidCmdDriver, IBaseDevice);
        _RegisteInterfaceCMD(HidCmdDriver, IInteractiveTrans);
        _RegisteInterfaceCMD(HidCmdDriver, ITimeoutBehavior);
    }
    /* Interface */
    LC_CMD_INTERFACE_GETTER(IBaseDevice, _activeDev);
    LC_CMD_INTERFACE_GETTER(IInteractiveTrans, _activeTrans);
    LC_CMD_INTERFACE_GETTER(ITimeoutBehavior, _activeTimeout);
    /**
     * @brief 枚举HID设备
     * @date 2017-02-27 20:18
     *
     * @param [in] Name : string [default:""] 需要匹配的部分名称
     * @param [in] VID : uint [default:0x00] 需要匹配的VID
     * @param [in] PID : uint [default:0x00] 需要匹配的PID
     * @param [in] IsDescription bool [default:true] 是否获取描述字符串
     * 
     * @retval Name : string 枚举到的设备名称
     * @retval Manufacturer : string 设备厂商名称
     * @retval VID : uint 匹配到的VID
     * @retval PID : uint 匹配到的PID
     * @retval Count : uint 枚举到的设备数目
     */
    LC_CMD_METHOD(EnumDevice)
    {
        list_t<HidDevice::device_info> devlist;
        bool isDescription = arg["IsDescription"].To<bool>(true);
        _hiddev.EnumDevice(devlist, isDescription);

        string name = arg["Name"].To<string>();
        uint vid = arg["VID"].To<uint>(0x00);
        uint pid = arg["PID"].To<uint>(0x00);
        list_t<HidDevice::device_info>::iterator itr;
        size_t count = 0;
        ByteArray sName(name.c_str(), name.length());
        for(itr = devlist.begin();itr != devlist.end();++itr)
        {
            if(!sName.IsEmpty() && !StringConvert::Contains(itr->Name.c_str(), sName))
                continue;
            if(vid != 0x00 && itr->Vid != vid)
                continue;
            if(pid != 0x00 && itr->Pid != pid)
                continue;

            rlt.Put("Name", itr->Name);
            rlt.Put("Manufacturer", itr->Manufacturer);
            rlt.Put("PID", _hex(itr->Pid));
            rlt.Put("VID", _hex(itr->Vid));
            ++count;
        }
        rlt.Put("Count", ArgConvert::ToString(count));
        return true;
    }
    /**
     * @brief 打开HID设备
     * @date 2016-09-26 23:28
     * 
     * @param [in] Name : string 需要打开的设备名称
     *
     * @param [in] VID : uint 需要打开的VID
     * @param [in] PID : uint 需要打开的PID
     *
     * @warning Name和VID,PID任选一个进行连接,优先判断Name
     * 
     * @param [in] FixedInput : uint [default:0] 发送数据时长度字节位数
     * @param [in] FixedOutput : uint [default:0] 接收数据时长度字节位数
     * @param [in] TransmitMode : string [default:Control] 通信模式
     * - 模式:
     *  - Control : 控制传输
     *  - Interrupt : 中断传输
     *  .
     */
    LC_CMD_METHOD(Open)
    {
        DevHelper::ErrEnum err = DevHelper::EnumERROR;
        string name;
        bool hasName = true;
        if(!arg["Name"].Get<string>(name))
        {
            string sVid;
            string sPid;
            if(!arg.Get("VID", sVid) || !arg.Get("PID", sPid))
            {
                _logErr(DeviceError::ArgErr, "缺少参数[Name],[VID],[PID]");
                return false;
            }
            uint vid = ArgConvert::FromString<uint>(sVid);
            uint pid = ArgConvert::FromString<uint>(sPid);
            err = HidDeviceHelper::OpenDevice<HidDevice>(_hiddev, vid, pid);
        }
        else
        {
            err = HidDeviceHelper::OpenDevice<HidDevice>(_hiddev, name.c_str());
        }
        switch(err)
        {
        case DevHelper::EnumERROR:
            _logErr(DeviceError::DevNotExistErr, "设备未连接");
            return false;
        case DevHelper::EnumFAILE:
            return false;
        }

        _hidcmd.FixedInput = arg["FixedInput"].To<size_t>(0);
        _hidcmd.FixedOutput = arg["FixedOutput"].To<size_t>(0);

        HidDevice::TransmitMode transmitMode = HidDevice::StringToMode(arg["TransmitMode"].To<string>().c_str());
        _hiddev.SetTransmitMode(transmitMode);

        return true;
    }
    /// 返回设备是否打开
    LC_CMD_METHOD(IsOpen)
    {
        ASSERT_FuncErr(_hiddev.IsOpen(), DeviceError::DevAlreadyCloseErr);
        return true;
    }
    /// 关闭设备
    LC_CMD_METHOD(Close)
    {
        _hiddev.Close();
        return true;
    }

    LC_CMD_TIMEOUT(_hiddev);
    LC_CMD_CANCEL(_hiddev);
    LC_CMD_INTERACTIVETRANS(_hidcmd);
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_HIDCMDDRIVER_H_
//========================================================= 